﻿using Castle.Core.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WJP.Dependency;

namespace WJP.ComponentModel
{
    /// <summary>
    /// 插件管理器
    /// </summary>
    public class PluginManager : IPluginManager
    {
        public ILogger Logger { get; set; }

        private List<PluginInfo> _pluginInfos;

        private readonly List<IPluginSource> _pluginSources;

        public IApp App { get; private set; }

        private readonly IIocManager _iocManager;

        /// <summary>
        /// 
        /// </summary>
        public PluginManager(IIocManager iocManager)
        {
            _iocManager = iocManager;
            Logger = NullLogger.Instance;

            _pluginSources = new List<IPluginSource>();
            _pluginInfos = new List<PluginInfo>();

            _pluginSources.Add(new FolderPluginSource(PlatformEnvironment.MapAbsolutePath("Domain")));
            _pluginSources.Add(new FolderPluginSource(PlatformEnvironment.MapAbsolutePath("UI")));
        }

        /// <summary>
        /// 添加插件加载源，默认已添加Domain和UI目录的插件
        /// </summary>
        /// <param name="pluginSource"></param>
        public void AddPluginSource(IPluginSource pluginSource)
        {
            _pluginSources.Add(pluginSource);
        }

        /// <summary>
        /// 添加插件加载源
        /// </summary>
        /// <param name="pluginSources"></param>
        public void AddPluginSourceRange(IEnumerable<IPluginSource> pluginSources)
        {
            _pluginSources.AddRange(pluginSources);
        }

        /// <summary>
        /// 设置启动类
        /// </summary>
        /// <param name="app"></param>
        public void SetApp(IApp app)
        {
            App = app;
        }

        /// <summary>
        /// 初始化插件管理器
        /// </summary>
        public void Initialize()
        {
            LoadAllPlugins();
        }

        private void LoadAllPlugins()
        {
            Logger.Debug("加载插件...");

            List<PluginInfo> plugins = new List<PluginInfo>();

            foreach (var pluginSource in _pluginSources)
            {
                foreach (var pluginType in pluginSource.GetPlugins())
                {
                    _iocManager.RegisterIfNot(pluginType);
                    var pluginObject = _iocManager.Resolve(pluginType) as PluginBase;
                    if (pluginObject == null)
                        throw new AppException("这个类型不是一个插件类型，插件必须继承自AppPlugin：{0}".FormatArgs(pluginType.AssemblyQualifiedName));

                    pluginObject.IocManager = _iocManager;
                    var pluginInfo = new PluginInfo(pluginType.Assembly, pluginObject, pluginType);
                    plugins.Add(pluginInfo);

                    Logger.Debug("加载插件：{0}".FormatArgs(pluginType.AssemblyQualifiedName));
                }
            }

            Logger.Debug("总共发现了{0}个插件".FormatArgs(plugins.Count));

            //TODO: 排序、设置插件的依赖关系
            _pluginInfos.AddRange(LoadSortedPlugins(plugins));
            EnsureAppCorePluginToBeFirst(_pluginInfos);

            _pluginInfos.ForEach(p => p.Instance.PreInitialize());
            _pluginInfos.ForEach(p => p.Instance.Initialize(App));
            _pluginInfos.ForEach(p => p.Instance.PostInitialize());

            Logger.Debug("{0}个插件初始化完成".FormatArgs(_pluginInfos.Count));
        }

        /// <summary>
        /// 对插件排序和设置依赖关系
        /// </summary>
        /// <param name="assemblies"></param>
        /// <returns></returns>
        private List<PluginInfo> LoadSortedPlugins(IEnumerable<PluginInfo> assemblies)
        {
            List<PluginInfo> results = new List<PluginInfo>();
            var groupAssemblys = assemblies.GroupBy(a => a.Instance.SetupLevel).OrderBy(g => g.Key);
            int num = 1;
            foreach (IEnumerable<PluginInfo> list in groupAssemblys)
            {
                var sorted = SortByReference(list);
                sorted.ForEach(p => p.SetupIndex = num++);
                results.AddRange(sorted);
            }
            return results;
        }

        /// <summary>
        /// 对引用的程序集排序
        /// </summary>
        /// <param name="sameLevelPlugin"></param>
        /// <returns></returns>
        private List<PluginInfo> SortByReference(IEnumerable<PluginInfo> sameLevelPlugin)
        {
            // TODO:程序集排序算法
            List<PluginInfo> pluginInfos = new List<PluginInfo>();
            foreach (var pluginInfo in sameLevelPlugin)
            {
                pluginInfos.AddIfNotContaines(pluginInfo);
                var referencedAssemblies = pluginInfo.Assembly.GetReferencedAssemblies();
                if (!referencedAssemblies.Any(p => sameLevelPlugin.Any(s => s.Assembly.FullName == p.FullName)))
                {
                    InsertOrMoveFront(pluginInfos, null, pluginInfo);
                    continue;
                }
                foreach (var refAssembly in referencedAssemblies)
                {
                    var targetPlugin = sameLevelPlugin.FirstOrDefault(p => p.Assembly.FullName == refAssembly.FullName);
                    if (targetPlugin != null)
                    {
                        InsertOrMoveFront(pluginInfos, pluginInfo, targetPlugin);
                    }
                }
            }

            return pluginInfos;
        }

        /// <summary>
        /// 将targetPlugin插入到sourcePlugin的前面
        /// </summary>
        /// <param name="pluginInfos"></param>
        /// <param name="sourcePlugin"></param>
        /// <param name="targetPlugin"></param>
        private void InsertOrMoveFront(List<PluginInfo> pluginInfos, PluginInfo sourcePlugin, PluginInfo targetPlugin)
        {
            if (sourcePlugin == null)
            {
                if (pluginInfos.Contains(targetPlugin))
                    pluginInfos.Remove(targetPlugin);
                pluginInfos.Insert(0, targetPlugin);
                return;
            }
            if (!pluginInfos.Contains(sourcePlugin))
                return;

            if (pluginInfos.Contains(targetPlugin))
                pluginInfos.Remove(targetPlugin);

            var index = pluginInfos.IndexOf(sourcePlugin);
            pluginInfos.Insert(index, targetPlugin);
        }

        /// <summary>
        /// 确保<see cref="AppCorePlugin"/>插件为第一个启动的插件
        /// </summary>
        /// <param name="pluginInfos"></param>
        private void EnsureAppCorePluginToBeFirst(List<PluginInfo> pluginInfos)
        {
            var corePlugin = pluginInfos.FirstOrDefault(p => p.Type == typeof(AppCorePlugin));
            if (corePlugin == null)
            {
                _iocManager.RegisterIfNot(typeof(AppCorePlugin));
                var coreInfo = new PluginInfo(
                    typeof(AppCorePlugin).Assembly,
                    _iocManager.Resolve<AppCorePlugin>(),
                    typeof(AppCorePlugin))
                { SetupIndex = 0 };
                coreInfo.Instance.IocManager = _iocManager;
                pluginInfos.Insert(0, coreInfo);
            }
            else
            {
                var index = pluginInfos.FindIndex(p => p.Type == typeof(AppCorePlugin));
                if (index <= 0)
                    return;

                var coreInfo = pluginInfos[index];
                coreInfo.SetupIndex = 0;
                pluginInfos.RemoveAt(index);
                pluginInfos.Insert(0, coreInfo);
            }
        }

        /// <summary>
        /// 获取所有插件的信息
        /// </summary>
        /// <returns></returns>
        public IEnumerable<PluginInfo> GetPluginInfos()
        {
            return _pluginInfos;
        }

        public void ShutdownPlugins()
        {
            Logger.Debug("开始卸载插件".Translate());

            _pluginInfos.Reverse();
            _pluginInfos.ForEach(p => p.Instance.Shutdown());

            Logger.Debug("插件卸载完成".Translate());
        }
    }
}
